#include "STLLoader.h"

#include "STLLoader.h"
#include "ParserBuffer.h"
#include "RWUtils.h"
#include <cstring>

namespace soft_renderer
{
	STLLoader::STLLoader(Geometry& geom) : _geom(geom)
	{
	}

	bool STLLoader::pattern_check(const char* str, int s, const char* pattern, int len)
	{
		for (int i = 0; i < len; i++)
		{
			if (str[i + s] != pattern[i])
			{
				return false;
			}
		}
		return true;
	}

	void STLLoader::load(std::string filename)
	{
		std::ifstream is(filename, std::ios::binary);
		if (is.fail()) return;

		// is.seekg(0, std::ios::end);
		// int fileSize = is.tellg();
		char buffer[100];
		is.read(buffer, 100);
		bool isBinary = false;
		if (!pattern_check(buffer, 0, "solid", 5))
		{
			isBinary = true;
		}
		else
		{
			is.seekg(-1024, std::ios::end);
			is.read(buffer, 1024);
			if (strstr(buffer, "endsolid") == nullptr)
			{
				isBinary = true;
			}
		}

		std::vector<float>& vertexArray = _geom.vertexArray();
		std::vector<uint32_t>& faceArray = _geom.faceArray();

		if (isBinary)
		{
			is.seekg(80);
			int a = is.tellg();
			uint32_t n_tris;
			is.read((char*)&n_tris, sizeof(uint32_t));
			// swapEndian(n_tris);
			int REAL32_SIZE_3 = sizeof(float) * 3;
			int UINT16_SIZE = sizeof(uint16_t);
			float real[3];
			for (int i = 0, j = 0; i < n_tris; i++, j += 3)
			{
				is.seekg(REAL32_SIZE_3, std::ios::cur);
				is.read((char*)&real[0], REAL32_SIZE_3);
				vertexArray.push_back(real[0]);
				vertexArray.push_back(real[1]);
				vertexArray.push_back(real[2]);
				is.read((char*)&real[0], REAL32_SIZE_3);
				vertexArray.push_back(real[0]);
				vertexArray.push_back(real[1]);
				vertexArray.push_back(real[2]);
				is.read((char*)&real[0], REAL32_SIZE_3);
				vertexArray.push_back(real[0]);
				vertexArray.push_back(real[1]);
				vertexArray.push_back(real[2]);
				is.seekg(UINT16_SIZE, std::ios::cur);
				faceArray.push_back(j);
				faceArray.push_back(j + 1);
				faceArray.push_back(j + 2);
			}
		}
		else
		{
			is.seekg(0, std::ios::end);
			int len = is.tellg();
			is.seekg(0, std::ios::beg);
			char* buffer = new char[len];
			is.read(buffer, len);
			ParserBuffer pb(buffer, len);
			pb.SkipLine();
			double x, y, z;
			int j = 0;
			while (true)
			{
				if (pb.ReachSTLEnd()) break;
				pb.SkipLine();
				pb.SkipLine();
				pb.SkipWS();
				for (int i = 0; i < 3; i++)
				{
					pb.SkipWord();
					x = pb.ReadDouble();
					y = pb.ReadDouble();
					z = pb.ReadDouble();
					vertexArray.push_back(x);
					vertexArray.push_back(y);
					vertexArray.push_back(z);
					pb.SkipWS();
				}
				faceArray.push_back(j);
				faceArray.push_back(j + 1);
				faceArray.push_back(j + 2);
				j += 3;
				pb.SkipLine();
				pb.SkipLine();
			}
		}

		_geom.computeVertexNormals();
	}
}

